# -*- coding: utf-8 -*-
# @Time    : 2021-02-18 10:51
# @Author  : Daniel

import math
import random
from itertools import permutations, zip_longest, product, chain

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10]

form_str_list = [
    # 数字 运算符 数字 运算符 数字 运算符 数字
    # 一个括号 的情况
    '(%s %s %s) %s %s %s %s',
    '(%s %s %s %s %s) %s %s',
    # '(%s %s %s %s %s %s %s)',
    '%s %s (%s %s %s) %s %s',
    '%s %s (%s %s %s %s %s)',
    '%s %s %s %s (%s %s %s)',
    # 两个括号 的情况
    '(%s %s %s) %s (%s %s %s)',
    '( (%s %s %s) %s %s) %s %s',
    '( %s %s (%s %s %s)) %s %s',
    '%s %s ((%s %s %s) %s %s)',
    '%s %s (%s %s (%s %s %s))',
    # 三个括号是重复的,就不用罗列出来了
]


def gen_nums():
    return random.choice(nums), random.choice(nums), random.choice(nums), random.choice(nums)


def calc(src, target):
    '''
    计算24点
    :param src: 源数据，list， 或者元组
    :param target: 目标数字，int
    :return:
    '''

    # 20240222 修改，列出所有可能的方案
    # todo 计算结果剔除重复内容，比如加不加括号等价的情况

    res_list = []

    def get_all_opera_seq_list():
        opera_list = ['+', '-', '*', '/']
        return product(opera_list, repeat=3)

    data_seq_list = permutations(src)

    for data_seq in data_seq_list:
        opera_seq_list = get_all_opera_seq_list()
        for opera_seq in opera_seq_list:
            value = zip_longest(data_seq, opera_seq, fillvalue='')
            value_chain = chain.from_iterable(value)

            args = tuple(list(value_chain)[:7])
            # print(args)

            for form_str in form_str_list:
                # print(form_str)
                calc_str = form_str % args

                try:
                    res = eval(calc_str)
                except ZeroDivisionError:
                    continue

                # print(calc_str)

                if math.isclose(res, target):
                    res_list.append((calc_str, res))
    # 剔除完全一致的结果
    res_list = list(set(res_list))
    return res_list


if __name__ == '__main__':
    nums = gen_nums()
    print('获取随机数:', nums)

    print('开始计算')
    methods = calc(nums, 24)
    print('计算结果')
    if len(methods) == 0:
        print('无法计算')
    else:
        for method in methods:
            print('%s = %s' % method)
